/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.gidoo.xmldb;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLSyntaxErrorException;
import java.sql.Statement;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionGroup;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;

/**
 *
 * @author thomas
 */
public class CMD
{

  /**
   * @param args the command line arguments
   */
  public static void main(String[] args)
  {
    Options opts = new Options();
    OptionGroup actionsGroup = new OptionGroup();

    Option createOpt = new Option("c", "create", false,
      "(re-) create the database. WILL DELETE ALL OLD CONTENT!");

    Option listOpt = new Option("l", "list", false,
      "lists all documents of the database");

    Option showOpt = new Option("s", "show", false,
      "shows a document (or a subpart given by an id) XML");

    Option execOpt = new Option("e", "exec", true,
      "executes a SQL-statement with a timeout of 30 seconds");
    execOpt.setArgName("sql-statement");

    Option importOpt = new Option("I", "import", true,
      "load a file into the database");
    importOpt.setArgName("file-path");

    Option deleteOpt = new Option("x", "delete", false,
      "delete an document");

    actionsGroup.addOption(createOpt);
    actionsGroup.addOption(listOpt);
    actionsGroup.addOption(showOpt);
    actionsGroup.addOption(execOpt);
    actionsGroup.addOption(importOpt);
    actionsGroup.addOption(deleteOpt);

    actionsGroup.setRequired(true);
    opts.addOptionGroup(actionsGroup);

    Option dbOpt = new Option("d", "db", true, "The database to talk with (or create).");
    dbOpt.setRequired(true);

    opts.addOption(dbOpt);

    opts.addOption("f", "flush", true,
      "The number of parsers events after which the import statemens should be flushed.");
    opts.addOption("n", "name", true,
      "The internal document name.");
    opts.addOption("i", "id", true,
      "The ID to use");

    if(args.length == 0 || args[0].equalsIgnoreCase("--help") || args[0].equalsIgnoreCase("-h"))
    {
      printHelp(opts);
      return;
    }


    Logger logParser = Logger.getLogger(Parser.class.getName());
    try
    {
      FileHandler fh = new FileHandler("parsing.log");
      fh.setFormatter(new SimpleFormatter());
      fh.setLevel(Level.ALL);
      logParser.addHandler(fh);
    }
    catch(IOException ex)
    {
      Logger.getLogger(CMD.class.getName()).log(Level.SEVERE, null, ex);
    }
    catch(SecurityException ex)
    {
      Logger.getLogger(CMD.class.getName()).log(Level.SEVERE, null, ex);
    }
    logParser.setLevel(Level.ALL);

    CommandLineParser cli = new GnuParser();
    try
    {
      CommandLine cmd = cli.parse(opts, args);

      if(cmd.hasOption("create"))
      {
        GidooXMLDBManager.initDB(cmd.getOptionValue("db"));
      }
      else if(cmd.hasOption("import"))
      {
        try
        {
          if(cmd.hasOption("name"))
          {
            long flushCounter = -1;
            if(cmd.hasOption("flush"))
            {
              flushCounter = Long.parseLong(cmd.getOptionValue("flush"));
            }

            GidooXMLDBManager.importDocument(
              cmd.getOptionValue("db"), cmd.getOptionValue("name"),
              new FileReader(new File(cmd.getOptionValue("import"))),
              flushCounter);
          }
          else
          {
            System.out.println("\nYou have to specify a document name");
            printHelp(opts);
          }
        }
        catch(Exception ex)
        {
          Logger.getLogger(CMD.class.getName()).log(Level.SEVERE, null, ex);
        }
      }
      else if(cmd.hasOption("delete"))
      {
        if(cmd.hasOption("name"))
        {
          GidooXMLDBManager.deleteDocument(cmd.getOptionValue("db"),
            cmd.getOptionValue("name"));
        }
        else
        {
          System.out.println("\nYou have to specify a document name");
          printHelp(opts);
        }
      }
      else if(cmd.hasOption("list"))
      {
        querySQL(cmd.getOptionValue("db"), "select * from documents");
      }
      else if(cmd.hasOption("show"))
      {
        RestoreXML rsXML = null;

        PrintWriter outWriter = new PrintWriter(System.out);
        Connection conn = ConnectionHelper.connect2DB(cmd.getOptionValue("db"), false);

        boolean parse = false;

        if(cmd.hasOption("name"))
        {
          rsXML = new RestoreXML(cmd.getOptionValue("name"), conn, outWriter);
          parse = true;          
        }
        else if(cmd.hasOption("id"))
        {
          try
          {
            rsXML = new RestoreXML(Long.parseLong(cmd.getOptionValue("id")), conn, outWriter);
            parse = true;
          }
          catch(NumberFormatException ex)
          {
            Logger.getLogger(CMD.class.getName()).log(Level.SEVERE, null, ex);
          }
        }

        if(parse)
        {
          rsXML.startParsing();
          outWriter.println();
          outWriter.flush();
        }
        else
        {
          System.out.println("\nYou have to provide a document name or an element id");
          printHelp(opts);
        }
      }
      else if(cmd.hasOption("exec"))
      {
        querySQL(cmd.getOptionValue("db"), cmd.getOptionValue("exec"));
      }
      else
      {
        // default, we don't know how to handle this
        printHelp(opts);
      }

    }
    catch(ParseException ex)
    {
      System.out.println(ex.getMessage());
      printHelp(opts);
    }

  }

  private static void printHelp(Options opts)
  {
    System.out.println();
    HelpFormatter f = new HelpFormatter();
    f.printHelp("java -jar gidooXMLDB.jar", opts);
  }

  private static void querySQL(String dbName, String sql)
  {
    Connection con = ConnectionHelper.connect2DB(dbName, false);
    try
    {
      Statement stmt = con.createStatement();
      stmt.setQueryTimeout(30);
      ResultSet rs = stmt.executeQuery(sql);
      int count = rs.getMetaData().getColumnCount();

      int[] sizeOfCaption = new int[count];

      for(int j = 1; j <=
        count; j++)
      {
        String n = rs.getMetaData().getColumnName(j);
        System.out.print("| " + n + "\t\t");
        sizeOfCaption[j - 1] = n.length();
      }

      System.out.println();
      for(int j = 1; j <=
        count; j++)
      {
        System.out.print("| ");
        for(int k = 0; k <
          sizeOfCaption[j - 1]; k++)
        {
          System.out.print("-");
        }

        System.out.print("\t\t");
      }

      System.out.println();

      while(rs.next())
      {
        for(int i = 1; i <=
          count; i++)
        {
          Object o = rs.getObject(i);
          System.out.print("| " + (o == null ? "NULL" : o.toString()) + "\t\t");
        }

        System.out.println();
      }

    }
    catch(SQLSyntaxErrorException ex)
    {
      System.err.println("syntax error:\n" + ex.getMessage());
    }
    catch(SQLException ex)
    {
      Logger.getLogger(CMD.class.getName()).log(Level.SEVERE, null, ex);
    }

  }
}
